package own.rpc.bio;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import own.rpc.RPCServer;

public class BioRPCServerImpl implements RPCServer {

	private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

	private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();

	private static boolean isRunning = false;

	@Override
	public void start() throws IOException {
		ServerSocket server = new ServerSocket();
		server.bind(new InetSocketAddress(8888));
		isRunning = true;
		while (true) {
			executor.submit(new ServerTask(server.accept()));
		}
	}

	@Override
	public void stop() {
		isRunning = false;

	}

	@Override
	public void register(Class serviceInterface, Class serviceImpl) {
		serviceRegistry.put(serviceInterface.getName(), serviceImpl);
	}

	@Override
	public boolean isRuning() {
		return isRunning;
	}

	private static class ServerTask implements Runnable {
		Socket socket;

		public ServerTask(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			ObjectInputStream input = null;
			ObjectOutputStream output = null;
			try {
				input=new ObjectInputStream(socket.getInputStream());
				String serviceName=input.readUTF();
				String methodName=input.readUTF();
				Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
				Object[] objs=(Object[])input.readObject();
				
				Class service=serviceRegistry.get(serviceName);
				
				if(null==service){
					throw new IllegalAccessException(serviceName+" service name illegal !!!");
				}
				System.out.println("serviceName:"+serviceName);
				System.out.println("methodName:"+methodName);
				Method method=service.getMethod(methodName, parameterTypes);
				Object result=method.invoke(service.newInstance(), objs);
				output=new ObjectOutputStream(socket.getOutputStream());
				output.writeObject(result);
				
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				if(null!=input){
					try {
						input.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					input=null;
				}
				if(null!=output){
					try {
						output.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					output=null;
				}
			}
		}

	}
}
